home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / mbuf.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  13KB  |  633 lines

  1. /* mbuf (message buffer) primitives
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  *
  4.  * Mods by G1EMM
  5.  */
  6.  
  7. #include <stdio.h>
  8. #ifdef MSDOS
  9. #include <dos.h>        /* TEMP */
  10. #endif
  11. #include "global.h"
  12. #ifdef MSDOS
  13. #include <alloc.h>
  14. #endif
  15. #include "mbuf.h"
  16. #include "proc.h"
  17. #include "config.h"
  18.  
  19. #ifndef UNIX
  20.  
  21. /* Interrupt buffer pool */
  22. int Intqlen;                    /* Number of free mbufs on Intq */
  23. struct mbuf *Intq;              /* Mbuf pool for interrupt handlers */
  24. struct mbuf *Garbq;             /* List of buffers freed at interrupt time */
  25. long Ibuffail;                  /* Allocate failures */
  26. int Iminfree  = -1;             /* minimum free buffers */
  27.  
  28. void
  29. refiq()
  30. {
  31.     register struct mbuf *bp;
  32.     char i_state;
  33. #ifdef  PI              /* Temp hack to satisfy PI DMA requirements */
  34.     int32 dma_abs;  /* TEMP */
  35.     int16 dma_page; /* TEMP */
  36. #endif
  37.  
  38.     /* Empty the garbage */
  39.     if(Garbq != NULLBUF){
  40.         i_state = dirps();
  41.         bp = Garbq;
  42.         Garbq = NULLBUF;
  43.         restore(i_state);
  44.         free_p(bp);
  45.     }
  46.     /* Replenish interrupt buffer pool */ /* G1EMM and HB9RWM fix */
  47.     while((Intqlen < Nibufs) && (Memthresh < availmem()) ){
  48. #ifdef notdef
  49.     while(Intqlen < Nibufs){
  50. #endif
  51.     if((bp = alloc_mbuf(Ibufsize)) == NULLBUF)
  52.             break;
  53. #ifdef  PI              /* Temp hack to satisfy PI DMA requirements */
  54.         dma_abs = ((long)FP_SEG(bp->data) << 4) + (long)FP_OFF(bp->data);
  55.         dma_page = dma_abs >> 16;
  56.         if(((dma_abs+Ibufsize) >> 16) != dma_page){
  57.             i_state = dirps();
  58.             bp->next = Garbq;
  59.             Garbq = bp;
  60.             restore(i_state);
  61.             continue;
  62.         }
  63. #endif
  64.  
  65.         i_state = dirps();
  66.         bp->next = Intq;
  67.         Intq = bp;
  68.         Intqlen++;
  69.         restore(i_state);
  70.     }
  71.     if(Iminfree == -1)
  72.         Iminfree = Intqlen;
  73. }
  74.  
  75. void
  76. iqstat()
  77. {
  78.     tprintf("Intqlen %u Ibufsize %u Iminfree %u Ibuffail %lu\n",
  79.         Intqlen,Ibufsize,Iminfree,Ibuffail);
  80. }
  81.  
  82. void
  83. iqclear()
  84. {
  85.     Ibuffail = 0;
  86.     Iminfree = -1;
  87. }
  88. #endif
  89.  
  90. /* Allocate mbuf with associated buffer of 'size' bytes. If interrupts
  91.  * are enabled, use the regular heap. If they're off, use the special
  92.  * interrupt buffer pool.
  93.  */
  94. struct mbuf *
  95. alloc_mbuf(size)
  96. register int16 size;
  97. {
  98.     register struct mbuf *bp;
  99.  
  100. #ifndef UNIX
  101.     if(istate()){
  102. #endif
  103.         /* Interrupts are enabled, use the heap normally */
  104.         bp = (struct mbuf *)malloc((unsigned)(size + sizeof(struct mbuf)));
  105.         if(bp == NULLBUF)
  106.             return NULLBUF;
  107.         /* Clear just the header portion */
  108.         memset((char *)bp,0,sizeof(struct mbuf));
  109.         if((bp->size = size) != 0)
  110.             bp->data = (char *)(bp + 1);
  111.         bp->refcnt++;
  112. #ifndef UNIX
  113.     } else {
  114.         /* Interrupts are off, use special interrupt buffer pool */
  115.         if(size > Ibufsize || Intq == NULLBUF){
  116.             Ibuffail++;
  117.             return NULLBUF;
  118.         }
  119.         bp = Intq;
  120.         Intq = bp->next;
  121.         bp->next = NULLBUF;
  122.         Intqlen--;
  123.     }
  124.     if(Intqlen < Iminfree)
  125.         Iminfree = Intqlen;
  126. #endif
  127.     return bp;
  128. }
  129. /* Allocate mbuf, waiting if memory is unavailable */
  130. struct mbuf *
  131. ambufw(size)
  132. int16 size;
  133. {
  134.     register struct mbuf *bp;
  135.  
  136.     bp = (struct mbuf *)mallocw((unsigned)(size + sizeof(struct mbuf)));
  137.  
  138.     /* Clear just the header portion */
  139.     memset((char *)bp,0,sizeof(struct mbuf));
  140.     if((bp->size = size) != 0)
  141.         bp->data = (char *)(bp + 1);
  142.     bp->refcnt++;
  143.     return bp;
  144. }
  145.  
  146. /* Decrement the reference pointer in an mbuf. If it goes to zero,
  147.  * free all resources associated with mbuf.
  148.  * Return pointer to next mbuf in packet chain
  149.  */
  150. struct mbuf *
  151. free_mbuf(bp)
  152. register struct mbuf *bp;
  153. {
  154.     struct mbuf *bpnext;
  155.  
  156.     if(bp == NULLBUF)
  157.         return NULLBUF;
  158.  
  159.     bpnext = bp->next;
  160.     if(bp->dup != NULLBUF){
  161.         free_mbuf(bp->dup);     /* Follow indirection */
  162.         bp->dup = NULLBUF;
  163.     }
  164.     /* Decrement reference count. If it has gone to zero, free it. */
  165.     if(--bp->refcnt <= 0){
  166.     /* If interrupts are on, simply free the buffer.
  167.      * Otherwise put it on the garbage list where it
  168.      * will be freed by refiq() later with interrupts
  169.      * enabled.
  170.      */
  171. #ifndef UNIX
  172.     if(istate()){
  173. #endif
  174.         free((char *)bp);
  175. #ifndef UNIX
  176.     } else {
  177.         bp->refcnt = 1; /* Adjust */
  178.         /* free ibufsize buffers to the interrupt q, if not full. */
  179.         if(bp->size == Ibufsize && Intqlen < Nibufs) {
  180.         bp->next = Intq;
  181.         bp->anext = NULLBUF;
  182.         bp->data = (char *)(bp + 1);
  183.         bp->cnt = 0;
  184.         Intq = bp;
  185.         Intqlen++;
  186.         } else {
  187.         /* put on garbage queue */
  188.         bp->next = Garbq;
  189.         Garbq = bp;
  190.         }
  191.     }
  192. #endif
  193.     }
  194.     return bpnext;
  195. }
  196.  
  197. /* Free packet (a chain of mbufs). Return pointer to next packet on queue,
  198.  * if any
  199.  */
  200. struct mbuf *
  201. free_p(bp)
  202. register struct mbuf *bp;
  203. {
  204.     register struct mbuf *abp;
  205.  
  206.     if(bp == NULLBUF)
  207.         return NULLBUF;
  208.     abp = bp->anext;
  209.     while(bp != NULLBUF)
  210.         bp = free_mbuf(bp);
  211.     return abp;
  212. }               
  213. /* Free entire queue of packets (of mbufs) */
  214. void
  215. free_q(q)
  216. struct mbuf **q;
  217. {
  218.     register struct mbuf *bp;
  219.  
  220.     while((bp = dequeue(q)) != NULLBUF)
  221.         free_p(bp);
  222. }
  223.  
  224. /* Count up the total number of bytes in a packet */
  225. int16
  226. len_p(bp)
  227. register struct mbuf *bp;
  228. {
  229.     register int16 cnt = 0;
  230.  
  231.     while(bp != NULLBUF){
  232.         cnt += bp->cnt;
  233.         bp = bp->next;
  234.     }
  235.     return cnt;
  236. }
  237. /* Count up the number of packets in a queue */
  238. int16
  239. len_q(bp)
  240. register struct mbuf *bp;
  241. {
  242.     register int16 cnt;
  243.  
  244.     for(cnt=0;bp != NULLBUF;cnt++,bp = bp->anext)
  245.         ;
  246.     return cnt;
  247. }
  248.  
  249. /* Trim mbuf to specified length by lopping off end */
  250. void
  251. trim_mbuf(bpp,length)
  252. struct mbuf **bpp;
  253. int16 length;
  254. {
  255.     register int16 tot = 0;
  256.     register struct mbuf *bp;
  257.  
  258.     if(bpp == NULLBUFP || *bpp == NULLBUF)
  259.         return; /* Nothing to trim */
  260.  
  261.     if(length == 0){
  262.         /* Toss the whole thing */
  263.         free_p(*bpp);
  264.         *bpp = NULLBUF;
  265.         return;
  266.     }
  267.     /* Find the point at which to trim. If length is greater than
  268.      * the packet, we'll just fall through without doing anything
  269.      */
  270.     for( bp = *bpp; bp != NULLBUF; bp = bp->next){
  271.         if(tot + bp->cnt < length){
  272.             tot += bp->cnt;
  273.         } else {
  274.             /* Cut here */
  275.             bp->cnt = length - tot;
  276.             free_p(bp->next);
  277.             bp->next = NULLBUF;
  278.             break;
  279.         }
  280.     }
  281. }
  282. /* Duplicate/enqueue/dequeue operations based on mbufs */
  283.  
  284. /* Duplicate first 'cnt' bytes of packet starting at 'offset'.
  285.  * This is done without copying data; only the headers are duplicated,
  286.  * but without data segments of their own. The pointers are set up to
  287.  * share the data segments of the original copy. The return pointer is
  288.  * passed back through the first argument, and the return value is the
  289.  * number of bytes actually duplicated.
  290.  */
  291. int16
  292. dup_p(hp,bp,offset,cnt)
  293. struct mbuf **hp;
  294. register struct mbuf *bp;
  295. register int16 offset;
  296. register int16 cnt;
  297. {
  298.     register struct mbuf *cp;
  299.     int16 tot;
  300.  
  301.     if(cnt == 0 || bp == NULLBUF || hp == NULLBUFP){
  302.         if(hp != NULLBUFP)
  303.             *hp = NULLBUF;
  304.         return 0;
  305.     }
  306.     if((*hp = cp = alloc_mbuf(0)) == NULLBUF){
  307.         return 0;
  308.     }
  309.     /* Skip over leading mbufs that are smaller than the offset */
  310.     while(bp != NULLBUF && bp->cnt <= offset){
  311.         offset -= bp->cnt;
  312.         bp = bp->next;
  313.     }
  314.     if(bp == NULLBUF){
  315.         free_mbuf(cp);
  316.         *hp = NULLBUF;
  317.         return 0;       /* Offset was too big */
  318.     }
  319.     tot = 0;
  320.     for(;;){
  321.         /* Make sure we get the original, "real" buffer (i.e. handle the
  322.          * case of duping a dupe)
  323.          */
  324.         if(bp->dup != NULLBUF)
  325.             cp->dup = bp->dup;
  326.         else
  327.             cp->dup = bp;
  328.  
  329.         /* Increment the duplicated buffer's reference count */
  330.         cp->dup->refcnt++;
  331.  
  332.         cp->data = bp->data + offset;
  333.         cp->cnt = min(cnt,bp->cnt - offset);
  334.         offset = 0;
  335.         cnt -= cp->cnt;
  336.         tot += cp->cnt;
  337.         bp = bp->next;
  338.         if(cnt == 0 || bp == NULLBUF || (cp->next = alloc_mbuf(0)) == NULLBUF)
  339.             break;
  340.         cp = cp->next;
  341.     }
  342.     return tot;
  343. }
  344. /* Copy first 'cnt' bytes of packet into a new, single mbuf */
  345. struct mbuf *
  346. copy_p(bp,cnt)
  347. register struct mbuf *bp;
  348. register int16 cnt;
  349. {
  350.     register struct mbuf *cp;
  351.     register char *wp;
  352.     register int16 n;
  353.  
  354.     if(bp == NULLBUF || cnt == 0 || (cp = alloc_mbuf(cnt)) == NULLBUF)
  355.         return NULLBUF;
  356.     wp = cp->data;
  357.     while(cnt != 0 && bp != NULLBUF){
  358.         n = min(cnt,bp->cnt);
  359.         memcpy(wp,bp->data,(size_t)n);
  360.         wp += n;
  361.         cp->cnt += n;
  362.         cnt -= n;
  363.         bp = bp->next;
  364.     }
  365.     return cp;
  366. }
  367. /* Copy and delete "cnt" bytes from beginning of packet. Return number of
  368.  * bytes actually pulled off
  369.  */
  370. int16
  371. pullup(bph,buf,cnt)
  372. struct mbuf **bph;
  373. char *buf;
  374. int16 cnt;
  375. {
  376.     register struct mbuf *bp;
  377.     int16 n,tot;
  378.  
  379.     tot = 0;
  380.     if(bph == NULLBUFP)
  381.         return 0;
  382.     while(cnt != 0 && (bp = *bph) != NULLBUF){
  383.         n = min(cnt,bp->cnt);
  384.         if(buf != NULLCHAR){
  385.             if(n == 1)      /* Common case optimization */
  386.                 *buf = *bp->data;
  387.             else if(n > 1)
  388.                 memcpy(buf,bp->data,(size_t)n);
  389.             buf += n;
  390.         }
  391.         tot += n;
  392.         cnt -= n;
  393.         bp->data += n;
  394.         bp->cnt -= n;           
  395.         if(bp->cnt == 0){
  396.             /* If this is the last mbuf of a packet but there
  397.              * are others on the queue, return a pointer to
  398.              * the next on the queue. This allows pullups to
  399.              * to work on a packet queue
  400.              */
  401.             if(bp->next == NULLBUF && bp->anext != NULLBUF){
  402.                 *bph = bp->anext;
  403.                 free_mbuf(bp);
  404.             } else
  405.                 *bph = free_mbuf(bp);
  406.         }
  407.     }
  408.     return tot;
  409. }
  410. /* Append mbuf to end of mbuf chain */
  411. void
  412. append(bph,bp)
  413. struct mbuf **bph;
  414. struct mbuf *bp;
  415. {
  416.     register struct mbuf *p;
  417.     char i_state;
  418.  
  419.     if(bph == NULLBUFP || bp == NULLBUF)
  420.         return;
  421.     
  422.     i_state=dirps();
  423.     if(*bph == NULLBUF){
  424.         /* First one on chain */
  425.         *bph = bp;
  426.     } else {
  427.         for(p = *bph ; p->next != NULLBUF ; p = p->next)
  428.             ;
  429.         p->next = bp;
  430.     }
  431.     restore(i_state);
  432.     psignal(bph,1);
  433. }
  434. /* Insert specified amount of contiguous new space at the beginning of an
  435.  * mbuf chain. If enough space is available in the first mbuf, no new space
  436.  * is allocated. Otherwise a mbuf of the appropriate size is allocated and
  437.  * tacked on the front of the chain.
  438.  *
  439.  * This operation is the logical inverse of pullup(), hence the name.
  440.  */
  441. struct mbuf *
  442. pushdown(bp,size)
  443. register struct mbuf *bp;
  444. int16 size;
  445. {
  446.     register struct mbuf *nbp;
  447.  
  448.     /* Check that bp is real, that it hasn't been duplicated, and
  449.      * that it itself isn't a duplicate before checking to see if
  450.      * there's enough space at its front.
  451.      */
  452.     if(bp != NULLBUF && bp->refcnt == 1 && bp->dup == NULLBUF
  453.      && bp->data - (char *)(bp+1) >= size){
  454.         /* No need to alloc new mbuf, just adjust this one */
  455.         bp->data -= size;
  456.         bp->cnt += size;
  457.     } else {
  458.         nbp = ambufw(size);
  459.         nbp->next = bp;
  460.         nbp->cnt = size;
  461.         bp = nbp;
  462.     }
  463.     return bp;
  464. }
  465. /* Append packet to end of packet queue */
  466. void
  467. enqueue(q,bp)
  468. struct mbuf **q;
  469. struct mbuf *bp;
  470. {
  471.     register struct mbuf *p;
  472.     char i_state;
  473.  
  474.     if(q == NULLBUFP || bp == NULLBUF)
  475.         return;
  476.     i_state = dirps();
  477.     if(*q == NULLBUF){
  478.         /* List is empty, stick at front */
  479.         *q = bp;
  480.     } else {
  481.         for(p = *q ; p->anext != NULLBUF ; p = p->anext)
  482.             ;
  483.         p->anext = bp;
  484.     }
  485.     restore(i_state);
  486.     psignal(q,1);
  487. }
  488. /* Unlink a packet from the head of the queue */
  489. struct mbuf *
  490. dequeue(q)
  491. register struct mbuf **q;
  492. {
  493.     register struct mbuf *bp;
  494.     char i_state;
  495.  
  496.     if(q == NULLBUFP)
  497.         return NULLBUF;
  498.     i_state = dirps();
  499.     if((bp = *q) != NULLBUF){
  500.         *q = bp->anext;
  501.         bp->anext = NULLBUF;
  502.     }
  503.     restore(i_state);
  504.     return bp;
  505. }       
  506.  
  507. /* Copy user data into an mbuf */
  508. struct mbuf *
  509. qdata(data,cnt)
  510. char *data;
  511. int16 cnt;
  512. {
  513.     register struct mbuf *bp;
  514.  
  515.     bp = ambufw(cnt);
  516.     memcpy(bp->data,data,(size_t)cnt);
  517.     bp->cnt = cnt;
  518.     return bp;
  519. }
  520. /* Copy mbuf data into user buffer */
  521. int16
  522. dqdata(bp,buf,cnt)
  523. struct mbuf *bp;
  524. char *buf;
  525. unsigned cnt;
  526. {
  527.     int16 tot;
  528.     unsigned n;
  529.     struct mbuf *bp1;
  530.  
  531.     if(buf == NULLCHAR)
  532.         return 0;
  533.     
  534.     tot = 0;
  535.     for(bp1 = bp;bp1 != NULLBUF; bp1 = bp1->next){
  536.         n = min(bp1->cnt,cnt);
  537.         memcpy(buf,bp1->data,n);
  538.         cnt -= n;
  539.         buf += n;
  540.         tot += n;
  541.     }
  542.     free_p(bp);
  543.     return tot;
  544. }
  545. /* Pull a 32-bit integer in host order from buffer in network byte order.
  546.  * On error, return 0. Note that this is indistinguishable from a normal
  547.  * return.
  548.  */
  549. int32
  550. pull32(bpp)
  551. struct mbuf **bpp;
  552. {
  553.     char buf[4];
  554.  
  555.     if(pullup(bpp,buf,4) != 4){
  556.         /* Return zero if insufficient buffer */
  557.         return 0;
  558.     }
  559.     return get32(buf);
  560. }
  561. /* Pull a 16-bit integer in host order from buffer in network byte order.
  562.  * Return -1 on error
  563.  */
  564. long
  565. pull16(bpp)
  566. struct mbuf **bpp;
  567. {
  568.     char buf[2];
  569.  
  570.     if(pullup(bpp,buf,2) != 2){
  571.         return -1;              /* Nothing left */
  572.     }
  573.     return get16(buf);
  574. }
  575. /* Pull single character from mbuf */
  576. int
  577. pullchar(bpp)
  578. struct mbuf **bpp;
  579. {
  580.     char c;
  581.  
  582.     if(pullup(bpp,&c,1) != 1)
  583.         return -1;              /* Nothing left */
  584.     return (int)uchar(c);
  585. }
  586. int
  587. write_p(fp,bp)
  588. FILE *fp;
  589. struct mbuf *bp;
  590. {
  591.     while(bp != NULLBUF){
  592.         if(fwrite(bp->data,1,(size_t)bp->cnt,fp) != bp->cnt)
  593.             return -1;
  594.         bp = bp->next;
  595.     }
  596.     return 0;
  597. }
  598. #ifndef UNIX
  599. /* Reclaim unused space in a mbuf chain. If the argument is a chain of mbufs
  600.  * and/or it appears to have wasted space, copy it to a single new mbuf and
  601.  * free the old mbuf(s). But refuse to move mbufs that merely
  602.  * reference other mbufs, or that have other headers referencing them.
  603.  *
  604.  * Be extremely careful that there aren't any other pointers to
  605.  * (or into) this mbuf, since we have no way of detecting them here.
  606.  * This function is meant to be called only when free memory is in
  607.  * short supply.
  608.  */
  609. void
  610. mbuf_crunch(bpp)
  611. struct mbuf **bpp;
  612. {
  613.     register struct mbuf *bp = *bpp;
  614.     struct mbuf *nbp;
  615.  
  616.     if(bp->refcnt > 1 || bp->dup != NULLBUF){
  617.         /* Can't crunch, there are other refs */
  618.         return;
  619.     }
  620.     if(bp->next == NULLBUF && bp->cnt == bp->size){
  621.         /* Nothing to be gained by crunching */
  622.         return;
  623.     }
  624.     if((nbp = copy_p(bp,len_p(bp))) == NULLBUF){
  625.         /* Copy failed due to lack of (contiguous) space */
  626.         return;
  627.     }
  628.     nbp->anext = bp->anext;
  629.     free_p(bp);
  630.     *bpp = nbp;
  631. }
  632. #endif
  633.